/*
Copyright 2024 Flant JSC
Licensed under the Deckhouse Platform Enterprise Edition (EE) license.
See https://github.com/deckhouse/deckhouse/blob/main/ee/LICENSE
*/

package hooks

import (
	"context"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/yaml"

	"github.com/deckhouse/deckhouse/go_lib/dependency"
	. "github.com/deckhouse/deckhouse/testing/hooks"
)

var _ = Describe("Metallb hooks :: prepare services to migrate ::", func() {
	f := HookExecutionConfigInit(`{"metallb":{"internal":{}}}`, "")

	Context("There are 3 services, but only one  must be patched", func() {
		BeforeEach(func() {
			f.KubeStateSet("")
			f.ValuesSetFromYaml("metallb", []byte(`
"internal": {
  "ipAddressPoolToMLBCMap": {
    "pool-1": "autogenerated-zone-a",
    "pool-2": "autogenerated-zone-a"
  }
}
`))
			var moduleConfig ModuleConfig
			err := yaml.Unmarshal([]byte(`
---
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
  name: metallb
spec:
  enabled: true
  version: 1
  settings:
    speaker:
      nodeSelector:
        node-role.deckhouse.io/metallb: ""
    addressPools:
      - name: nginx-loadbalancer-pool1
        protocol: layer2
        addresses:
          - 192.168.70.100-192.168.70.110
      - name: nginx-loadbalancer-pool2
        protocol: layer2
        addresses:
          - 192.168.71.100-192.168.72.110
`), &moduleConfig)
			Expect(err).To(BeNil())
			objMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&moduleConfig)
			Expect(err).To(BeNil())
			unstructuredObj := &unstructured.Unstructured{Object: objMap}

			_, err = dependency.TestDC.MustGetK8sClient().
				Dynamic().Resource(schema.GroupVersionResource{
				Group:    "deckhouse.io",
				Version:  "v1alpha1",
				Resource: "moduleconfigs",
			}).Create(context.TODO(), unstructuredObj, metav1.CreateOptions{})
			Expect(err).To(BeNil())

			for _, clusterService := range []string{`
---
apiVersion: v1
kind: Service
metadata:
  name: nginx_serv1
  namespace: nginx1
spec:
  clusterIP: 1.2.3.4
  ports:
  - port: 7473
    protocol: TCP
    targetPort: 7473
  externalTrafficPolicy: Local
  internalTrafficPolicy: Cluster
  selector:
    app: nginx1
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 4.4.4.4
  conditions:
  - message: 2 of 3 public IPs were assigned
    reason: NotAllIPsAssigned
    status: "False"
    type: AllPublicIPsAssigned
  - message: status_mlbc
    reason: LoadBalancerClassBound
    status: "True"
    type: network.deckhouse.io/load-balancer-class`, `
---
apiVersion: v1
kind: Service
metadata:
  name: nginx_serv2
  namespace: nginx2
  finalizers:
  - service.kubernetes.io/load-balancer-cleanup
  annotations:
    network.deckhouse.io/load-balancer-ips: "7.7.7.7"
spec:
  clusterIP: 2.3.4.5
  ports:
  - port: 7474
    protocol: TCP
    targetPort: 7474
  externalTrafficPolicy: Local
  internalTrafficPolicy: Cluster
  selector:
    app: nginx2
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 5.5.5.5`, `
---
apiVersion: v1
kind: Service
metadata:
  name: nginx_serv3
  namespace: nginx3
  finalizers:
  - service.kubernetes.io/load-balancer-cleanup
  annotations:
    metallb.io/ip-allocated-from-pool: "pool-1"
    metallb.io/address-pool: "pool-2"
spec:
  clusterIP: 4.5.6.7
  ports:
  - port: 7475
    protocol: TCP
    targetPort: 7475
  externalTrafficPolicy: Local
  internalTrafficPolicy: Cluster
  selector:
    app: nginx3
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 12.12.12.12
    - ip: 13.13.13.13`} {
				var service v1.Service
				err := yaml.Unmarshal([]byte(clusterService), &service)
				Expect(err).To(BeNil())
				_, err = dependency.TestDC.MustGetK8sClient().
					CoreV1().
					Services(service.GetNamespace()).
					Create(context.TODO(), &service, metav1.CreateOptions{})
				Expect(err).To(BeNil())
			}

			f.RunHook()
		})

		It("Service must be patched", func() {
			Expect(f).To(ExecuteSuccessfully())
			k8sClient := f.BindingContextController.FakeCluster().Client
			patchedService, err := k8sClient.CoreV1().Services("nginx3").Get(
				context.TODO(),
				"nginx_serv3",
				metav1.GetOptions{},
			)
			Expect(err).To(BeNil())
			Expect(patchedService.Annotations["network.deckhouse.io/load-balancer-ips"]).To(
				Equal("12.12.12.12,13.13.13.13"),
			)
			Expect(patchedService.Annotations["network.deckhouse.io/metal-load-balancer-class"]).To(
				Equal("autogenerated-zone-a"),
			)
			Expect(patchedService.Finalizers).To(Equal([]string{}))
		})
	})
})
